package com.xiweicheng.test.springboot.mutil.ds.conf;

import java.util.Arrays;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;

import lombok.extern.slf4j.Slf4j;

@Configuration
@Slf4j
@EnableTransactionManagement
@MapperScan("com.xiweicheng.test.springboot.mutil.ds.mapper")
public class DsConf {

    @ConfigurationProperties(prefix = "spring.druid.ds1")
    @Bean(name = "ds1Prop")
    public DsProp ds1PropBean() {

        return new DsProp();
    }

    @ConfigurationProperties(prefix = "spring.druid.ds2")
    @Bean(name = "ds2Prop")
    public DsProp ds2PropBean() {

        return new DsProp();
    }

    @Bean(name = "ds1", destroyMethod = "close", initMethod = "init")
    @Primary
    public DataSource ds1Bean(DataSourceProperties properties) {

        DsProp dsProp = ds1PropBean();
        DruidDataSource datasource = new DruidDataSource();

        try {

            datasource.setUrl(properties.getUrl());
            datasource.setUsername(properties.getUsername());
            datasource.setPassword(properties.getPassword());
            datasource.setDriverClassName(properties.getDriverClassName());

            // configuration
            datasource.setInitialSize(dsProp.getInitialSize());
            datasource.setMinIdle(dsProp.getMinIdle());
            datasource.setMaxActive(dsProp.getMaxActive());
            datasource.setMaxWait(dsProp.getMaxWait());
            datasource.setTimeBetweenEvictionRunsMillis(dsProp.getTimeBetweenEvictionRunsMillis());
            datasource.setMinEvictableIdleTimeMillis(dsProp.getMinEvictableIdleTimeMillis());
            datasource.setValidationQuery(dsProp.getValidationQuery());
            datasource.setTestWhileIdle(dsProp.isTestWhileIdle());
            datasource.setTestOnBorrow(dsProp.isTestOnBorrow());
            datasource.setTestOnReturn(dsProp.isTestOnReturn());
            datasource.setPoolPreparedStatements(dsProp.isPoolPreparedStatements());
            datasource.setMaxPoolPreparedStatementPerConnectionSize(
                    dsProp.getMaxPoolPreparedStatementPerConnectionSize());
            datasource.setUseGlobalDataSourceStat(dsProp.isUseGlobalDataSourceStat());
            datasource.setFilters(dsProp.getFilters());

            WallConfig wallConfig = new WallConfig();
            wallConfig.setMultiStatementAllow(true);
            wallConfig.setNoneBaseStatementAllow(true);
            wallConfig.setCreateTableAllow(false);

            WallFilter wallFilter = new WallFilter();
            wallFilter.setConfig(wallConfig);

            datasource.setProxyFilters(Arrays.asList(wallFilter));

            return datasource;

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return properties.initializeDataSourceBuilder().build();

    }

    @Bean(name = "ds2", destroyMethod = "close", initMethod = "init")
    public DataSource ds2Bean(DataSourceProperties properties) {

        DsProp dsProp = ds2PropBean();
        DruidDataSource datasource = new DruidDataSource();

        try {

            datasource.setUrl(properties.getUrl());
            datasource.setUsername(properties.getUsername());
            datasource.setPassword(properties.getPassword());
            datasource.setDriverClassName(properties.getDriverClassName());

            // configuration
            datasource.setInitialSize(dsProp.getInitialSize());
            datasource.setMinIdle(dsProp.getMinIdle());
            datasource.setMaxActive(dsProp.getMaxActive());
            datasource.setMaxWait(dsProp.getMaxWait());
            datasource.setTimeBetweenEvictionRunsMillis(dsProp.getTimeBetweenEvictionRunsMillis());
            datasource.setMinEvictableIdleTimeMillis(dsProp.getMinEvictableIdleTimeMillis());
            datasource.setValidationQuery(dsProp.getValidationQuery());
            datasource.setTestWhileIdle(dsProp.isTestWhileIdle());
            datasource.setTestOnBorrow(dsProp.isTestOnBorrow());
            datasource.setTestOnReturn(dsProp.isTestOnReturn());
            datasource.setPoolPreparedStatements(dsProp.isPoolPreparedStatements());
            datasource.setMaxPoolPreparedStatementPerConnectionSize(
                    dsProp.getMaxPoolPreparedStatementPerConnectionSize());
            datasource.setUseGlobalDataSourceStat(dsProp.isUseGlobalDataSourceStat());
            datasource.setFilters(dsProp.getFilters());

            WallConfig wallConfig = new WallConfig();
            wallConfig.setMultiStatementAllow(true);
            wallConfig.setNoneBaseStatementAllow(true);
            wallConfig.setCreateTableAllow(false);

            WallFilter wallFilter = new WallFilter();
            wallFilter.setConfig(wallConfig);

            datasource.setProxyFilters(Arrays.asList(wallFilter));

            return datasource;

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return properties.initializeDataSourceBuilder().build();

    }

    @Bean(name = "mybatisSqlSessionFactoryBean")
    @ConfigurationProperties(prefix = "mybatis")
    public SqlSessionFactoryBean mybatisSqlSessionFactoryBean(@Qualifier("ds2") DataSource dataSource) {

        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    @Bean(name = "mybatisSqlSessionFactory")
    @Primary
    public SqlSessionFactory mybatisSqlSessionFactory(
            @Qualifier("mybatisSqlSessionFactoryBean") SqlSessionFactoryBean sqlSessionFactoryBean) throws Exception {

        return sqlSessionFactoryBean.getObject();
    }

    @Bean(name = "mybatisTransactionManager")
    public DataSourceTransactionManager mybatisTransactionManager(@Qualifier("ds2") DataSource dataSource) {

        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "transactionManager")
    @Primary
    public DataSourceTransactionManager transactionManager(@Qualifier("ds1") DataSource dataSource) {

        return new DataSourceTransactionManager(dataSource);
    }

    // @Bean(name = "mybatisSqlSessionTemplate")
    // @Primary
    // public SqlSessionTemplate mybatisSqlSessionTemplate(
    // @Qualifier("mybatisSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
    //
    // return new SqlSessionTemplate(sqlSessionFactory);
    // }

}
